/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						   dialog_high_score.cpp

	$Header: /game/dialog_high_score.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "dialog_high_score.h"

#include <assert.h>

#include "adventure_frame.h"
#include "adventure_map.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bitmap_layer_cache_window.h"
#include "blend_window.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "combat_model_window.h"
#include "combat_result.h"
#include "creature_icon_window.h"
#include "creature_select_window.h"
#include "creature_traits.h"
#include "creature_array.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "high_scores.h"
#include "interface_help.h"
#include "item_help_block.h"
#include "minimum_maximum.h"
#include "music.h"
#include "player.h"
#include "replace_keywords.h"
#include "report_combat_results.h"
#include "scrollbar.h"
#include "simple_dialog.h"
#include "sound.h"
#include "sound_cache.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "text_edit_window.h"
#include "toggle_button.h"
#include "town.h"


extern t_button_cache g_ok_button;
extern t_button_cache g_large_button;

// --------------------------------------------------------------------------
// Unnamed namespace
// --------------------------------------------------------------------------

namespace
{

	t_bitmap_group_cache g_layout_cache( "dialog.high_score" );
	t_bitmap_group_cache g_difficulty_icons( "icons.difficulty_60" );

	t_external_string const k_text_reset( "reset.high_score" );
	t_external_string const k_text_standard( "standard.high_score" );
	t_external_string const k_text_campaign( "campaign.high_score" );
	t_external_string const	k_text_done( "next.high_score" );
	t_external_string const k_text_title( "title.high_score" );
	t_external_string const k_text_score( "score.high_score" );
	t_external_string const k_text_days( "days.high_score" );
	t_external_string const k_text_confirm_reset( "confirm_reset.high_score" );

} // Unnamed namespace

// --------------------------------------------------------------------------
// t_high_score_dialog::t_impl class
// --------------------------------------------------------------------------

class t_high_score_dialog::t_impl
{
public:
	// --------------------------------------------------------------------------
	// local class for storing high score entries
	// --------------------------------------------------------------------------
	class t_high_score_dialog_entry
	{
	public:
		t_text_window *					m_days;
		t_window *						m_highlight;
		t_text_window *					m_map_name;
		t_text_window *					m_number;
		t_text_edit_window *			m_player_name;
		t_bitmap_layer_cache_window *	m_portrait_window;
		t_text_window *					m_score;
	};

	// Data members
	t_button *						m_campaign_button;
	t_window *						m_campaign_window;
	t_high_score_dialog_entry		m_campaign_entries[5];
	t_high_scores &					m_high_scores;
	int								m_first_score_index;
	t_bitmap_group_ptr				m_layout_ptr;
	t_high_score_dialog &			m_outer;
	t_scrollbar *					m_scrollbar;
	t_button *						m_standard_button;
	bool							m_standard_selected;
	t_window *						m_standard_window;
	t_high_score_dialog_entry		m_standard_entries[5];
	std::vector<t_toggle_button *>	m_highlights;	// Used for highlighting score entries, only need 5

	// Constructor
	t_impl(
		t_high_score_dialog &	outer,
		t_high_scores &			high_scores,
		bool					is_standard );

	// Member functions
	t_text_window* add_text( std::string const& text, std::string const& layer_name, 
							int size, bool size_explicit, bool center );
	t_text_window* add_text(	std::string const& text, std::string const& layer_name, 
								t_screen_point origin,
								bool center_horizontal, bool center_vertical,
								t_window * parent,
								int lines = 1 );

	void	campaign_clicked( t_button * button_ptr );
	void	initialize();
	void	ok_clicked( t_button * button_ptr );
	void	name_change( t_text_edit_window* );
	void	name_finished( t_text_edit_window* );
	void	reset_clicked( t_button * button_ptr );
	void	scrollbar_move( t_scrollbar * scrollbar, int value );
	void	show_scores(bool initing = false);
	void	standard_clicked( t_button * button_ptr );
	void	stop_editing();
};

// --------------------------------------------------------------------------
// t_high_score_dialog::t_impl members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_high_score_dialog::t_impl::t_impl(
	t_high_score_dialog &	outer,
	t_high_scores  &		high_scores,
	bool					is_standard )
	:	m_layout_ptr( g_layout_cache.get() ),
		m_outer( outer ),
		m_high_scores( high_scores ),
		m_first_score_index( 0 ),
		m_standard_selected( is_standard )
{
	t_bitmap_layer const * background_ptr = m_layout_ptr->find( "background" );
	m_outer.set_bitmap( background_ptr );

	initialize();

	t_screen_rect layout_rect = m_layout_ptr->get_rect();
	t_screen_rect parent_rect = m_outer.get_parent()->get_client_rect();
	m_outer.move( t_screen_rect( ( parent_rect.size() - layout_rect.size() ) / 2, layout_rect.size() ) );
}


// --------------------------------------------------------------------------
// dialog initialization
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::initialize()
{
	t_screen_point			point(0,0);
	t_screen_rect			rect;
	t_button *				button;
	t_help_block const&		help = get_help_block( "shared" );
	t_help_block const&		score_help = get_help_block( "high_score" );
	t_bitmap_layer const *	layer;
	t_window *				window;
	int						i;

	// Reset scores button
	layer = m_layout_ptr->find( "reset_button" );
	button = new t_button( g_large_button.get(), layer->get_rect().top_left(), &m_outer, k_text_reset );
	button->set_click_handler( bound_handler(*this, &t_high_score_dialog::t_impl::reset_clicked ) );
	set_help( button, score_help, "reset" );

	// Standard button
	layer = m_layout_ptr->find( "standard_button" );
	m_standard_button = new t_button( g_large_button.get(), layer->get_rect().top_left(), &m_outer, k_text_standard );
	m_standard_button->set_click_handler( bound_handler(*this, &t_high_score_dialog::t_impl::standard_clicked ) );
	set_help( m_standard_button, score_help, "standard" );

	// Campaign button
	layer = m_layout_ptr->find( "campaign_button" );
	m_campaign_button = new t_button( g_large_button.get(), layer->get_rect().top_left(), &m_outer, k_text_campaign );
	m_campaign_button->set_click_handler( bound_handler(*this, &t_high_score_dialog::t_impl::campaign_clicked ) );
	set_help( m_campaign_button, score_help, "campaign" );

	// Next button
	layer = m_layout_ptr->find( "ok_button" );
	button = new t_button( g_large_button.get(), layer->get_rect().top_left(), &m_outer, k_text_done );
	button->set_click_handler( bound_handler(*this, &t_high_score_dialog::t_impl::ok_clicked ) );
	set_help( button, help, "ok" );

    // Add scrollbar
	layer = m_layout_ptr->find( "scrollbar" );
	rect  = layer->get_rect();
	m_scrollbar = new t_scrollbar( rect.top_left(), rect.height(), &m_outer, 0, 10 );
	m_scrollbar->set_handler( bound_handler( *this, &t_high_score_dialog::t_impl::scrollbar_move ) );
	m_scrollbar->set_limits( 0, 5 ); // can only scroll half of the available ten slots
	m_scrollbar->set_position(0);

	// Show title text
	add_text( k_text_title, "title_text", 1, false, true );

	// Display score list
	t_screen_point					origin;
	t_bitmap_layer_cache_window*	portrait_window;	
	t_screen_point					base_offset;

	m_standard_window = new t_window( m_layout_ptr->get_rect(), k_completely_transparent, &m_outer );
	m_campaign_window = new t_window( m_layout_ptr->get_rect(), k_completely_transparent, &m_outer );
	m_campaign_window->set_visible( false );

	t_window *					parent = 0; 
	t_high_score_entry const *	high_score_entry = 0;
	t_high_score_dialog_entry *	entry = 0;

	base_offset = m_layout_ptr->find( "position_1" )->get_rect().top_left();

	// Create the 5 portrait frames and highlight buttons
	layer = m_layout_ptr->find( "creature_ring" );
	for( i = 0; i < 5; ++i )
	{
		rect = m_layout_ptr->find( format_string( "position_%d", (i+1) ) )->get_rect();
		origin = rect.top_left();

		/*
		** portrait
		*/
		origin -= base_offset;

		point = origin + layer->get_rect().top_left();
		window = new t_bitmap_layer_window( layer, point, &m_outer, false );

	}

	for( i = 0; i < 10; ++i )
	{
		if( m_standard_selected )
			high_score_entry = m_high_scores.get_standard_entry(i);
		else
			high_score_entry = m_high_scores.get_campaign_entry(i);

		// set the scroll index to the first new entry found
		if( m_first_score_index == 0 && high_score_entry->is_highlighted() )
			m_first_score_index = i;
	}

	for( i = 0; i < 10; ++i )
	{
		int ndx;
		if( i < 5 )
		{
			// show single scenario scores
			ndx = i;
			entry = &m_standard_entries[ndx];
			parent = m_standard_window;
		} else
		{
			// show campaign scores
			ndx = i%5;
			entry = &m_campaign_entries[ndx];
			parent = m_campaign_window;
		}

		rect = m_layout_ptr->find( format_string( "position_%d", (ndx+1) ) )->get_rect();
		origin = rect.top_left();
		origin -= base_offset;

		layer = m_layout_ptr->find( "creature_portrait" );
		point = origin + layer->get_rect().top_left();
		portrait_window = new t_bitmap_layer_cache_window(	t_bitmap_layer_ptr(), 
															point, 
															parent, false );
		entry->m_portrait_window = portrait_window;

		std::string text = "";
		entry->m_number			= add_text( text, "rank_text", origin, true, true, parent ); 
		entry->m_days			= add_text( text, "days_text", origin, true, true, parent ); 
		entry->m_score			= add_text( text, "score_text", origin, true, true, parent ); 

		//entry->m_player_name	= add_text( text, "player_text", origin, true, true, parent ); 

		// create a blue background
		entry->m_highlight = new t_blend_window( t_pixel_24(0,0,200), 3, rect, parent );
		entry->m_highlight->set_visible( false );

		t_text_edit_handler handler;
		t_screen_rect name_rect = m_layout_ptr->find( "player_text" )->get_rect();;
		name_rect += origin;

		entry->m_player_name = new t_text_edit_window( get_font( name_rect.height() ), name_rect, parent,
											 "", t_pixel_24(0,0,0) );
		entry->m_player_name->set_drop_shadow( true, t_pixel_24(200,200,200));
		entry->m_player_name->set_center_horizontal();
		entry->m_player_name->set_center_vertical();
		handler = bound_handler( *this, &t_high_score_dialog::t_impl::name_change );
		entry->m_player_name->set_change_handler( handler );
		handler = bound_handler( *this, &t_high_score_dialog::t_impl::name_finished );
		entry->m_player_name->set_end_edit_handler( handler );

		entry->m_map_name		= add_text( text, "map_text", origin, true, true, parent ); 
	}

	show_scores(true);

	m_scrollbar->set_position( m_first_score_index );
}

// ------------------------------------------------------------------
// save game dialog
// respond to a change in the edit box
// ------------------------------------------------------------------
void t_high_score_dialog::t_impl::name_change( t_text_edit_window* )
{
}

// ------------------------------------------------------------------
// save game dialog
// respond to a change in the edit box
// ------------------------------------------------------------------
void t_high_score_dialog::t_impl::name_finished( t_text_edit_window* )
{
	stop_editing();
	// user could have changed his name, write out the scores again
	write_high_scores_file( &m_high_scores );
}

// --------------------------------------------------------------------------
// Show campaign scores list button clicked
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::campaign_clicked( t_button * button_ptr )
{
	m_standard_selected = false;
	m_scrollbar->set_position( 0 );
	show_scores();
}

// --------------------------------------------------------------------------
// Next button clicked
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::ok_clicked( t_button * button_ptr )
{
	m_outer.close();
}

// --------------------------------------------------------------------------
// Reset score button clicked
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::reset_clicked( t_button * button_ptr )
{
	if( yes_no_dialog( k_text_confirm_reset, true ) )
	{
		t_high_scores_ptr high_scores = new t_high_scores();
		write_high_scores_file( high_scores );	// write out the new scores to disk
		m_high_scores = *high_scores;
		show_scores();
	}
}

// --------------------------------------------------------------------------
// Moved scroll bar
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::scrollbar_move( t_scrollbar* scrollbar, int value )
{
	stop_editing();
    m_first_score_index = value;
	show_scores();
}

// --------------------------------------------------------------------------
// Cancel editing of player name
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::stop_editing()
{
	int	i;
	t_high_score_dialog_entry *	entry = 0;
	t_high_score_entry *		high_score_entry = 0;

	int window_ndx = 0;
	for( i = m_first_score_index; i <= (m_first_score_index+4); ++i )
	{
		if( m_standard_selected )
		{
			entry = &m_standard_entries[window_ndx];
			high_score_entry = m_high_scores.get_standard_entry(i);
		}
		else
		{
			entry = &m_campaign_entries[window_ndx];
			high_score_entry = m_high_scores.get_campaign_entry(i);
		}

		if( high_score_entry->is_highlighted() )
		{
			entry->m_player_name->on_keyboard_focus_lost();
			high_score_entry->set_player_name( entry->m_player_name->get_text() );
			return;
		}

		++window_ndx;
	}
}

// --------------------------------------------------------------------------
// Show list of currently selected high scores
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::show_scores(bool initing)
{
	t_screen_point				origin;
	t_screen_point				point;
	t_screen_point				base_offset;
	t_high_score_entry const *	high_score_entry = 0;
	t_high_score_dialog_entry *	entry = 0;
	int							position_index = 1;
	int							i;
	t_bitmap_layer_ptr			icon;

	// Update the page that is visible
	m_standard_window->set_visible( m_standard_selected );
	m_campaign_window->set_visible( !m_standard_selected );

	// Update the button that is visible
	m_standard_button->enable( !m_standard_selected );
	m_campaign_button->enable( m_standard_selected );

	base_offset = m_layout_ptr->find( "position_1" )->get_rect().top_left();

	int window_ndx = 0;
	for( i = m_first_score_index; i <= (m_first_score_index+4); ++i )
	{
		if( m_standard_selected )
		{
			// show single scenario scores
			entry = &m_standard_entries[window_ndx];
			high_score_entry = m_high_scores.get_standard_entry(i);
		}
		else
		{
			// show campaign scores
			entry = &m_campaign_entries[window_ndx];
			high_score_entry = m_high_scores.get_campaign_entry(i);
		}

		// Pick out the creature icon associated with this score
		if ( high_score_entry->get_portrait_type() != k_creature_none )
		{
			icon = get_creature_portrait( high_score_entry->get_portrait_type(), 52 );
			entry->m_portrait_window->set_bitmap( icon );
		}
		entry->m_number->set_text( format_string( "%d", i+1 ) );
		entry->m_days->set_text( format_string( "%s: %s", k_text_days.c_str(), high_score_entry->get_days().c_str() ) ); 
		entry->m_score->set_text( format_string( "%s: %s", k_text_score.c_str(), high_score_entry->get_score().c_str() ) ); 
		entry->m_player_name->set_text( high_score_entry->get_player_name() ); 
		entry->m_map_name->set_text( high_score_entry->get_map_name() ); 
		if( high_score_entry->is_highlighted() )
		{
			entry->m_player_name->enable(true);
			entry->m_highlight->set_visible( true );
			if( initing )
				entry->m_player_name->begin_edit();
		} 
		else
		{
			entry->m_player_name->enable(false);
			entry->m_highlight->set_visible( false );
		}

		++window_ndx;
	}
}

// --------------------------------------------------------------------------
// Show single scenario score list button clicked
// --------------------------------------------------------------------------
void t_high_score_dialog::t_impl::standard_clicked( t_button * button_ptr )
{
	m_standard_selected = true;
	m_scrollbar->set_position( 0 );
	show_scores();
}

// ---------------------------------------------------------------------
// add a text item
// ---------------------------------------------------------------------
t_text_window* t_high_score_dialog::t_impl::add_text( std::string const& text, std::string const& layer_name, 
														int size, bool size_explicit, bool center )
{
	t_bitmap_layer const* layer;
	t_screen_rect         rect;
	t_text_window*        text_window;
	t_cached_font         font;

	layer = m_layout_ptr->find( layer_name );
	rect = layer->get_rect();
	if( size_explicit )
		font = get_font( size );
	else
		font = get_font( rect.height() / size );
	text_window = new t_text_window( font, rect, &m_outer, text, t_pixel_24(0,0,0));
	if( center )
		text_window->set_center_horizontal();
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200));
	return text_window;
}

// ---------------------------------------------------------------------
// add a text item
// ---------------------------------------------------------------------
t_text_window* t_high_score_dialog::t_impl::add_text(	std::string const& text, std::string const& layer_name, 
														t_screen_point origin,
														bool center_horizontal, bool center_vertical,
														t_window * parent,
														int lines )
{
	t_bitmap_layer const*	layer;
	t_screen_rect			rect;
	t_text_window*			text_window;
	t_cached_font			font;

	layer = m_layout_ptr->find( layer_name );
	rect = layer->get_rect();
	font = get_font( rect.height() / lines );
	rect += origin;
	text_window = new t_text_window( font, rect, parent, text, t_pixel_24(0,0,0));
	if( center_horizontal )
		text_window->set_center_horizontal();
	if( center_vertical )
		text_window->set_center_vertical();
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200));
	return text_window;
}

// --------------------------------------------------------------------------
// t_high_score_dialog members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
#pragma warning( push )
#pragma warning( disable: 4355 )
t_high_score_dialog::t_high_score_dialog(
	t_window *				parent_ptr,
	t_high_scores &			high_scores,
	bool					is_standard )
	:	t_bitmap_layer_window( 0, t_screen_point( 0, 0 ), parent_ptr ),
		m_impl_ptr( new t_impl( *this, high_scores, is_standard ) )
{
}
#pragma warning( pop )

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_high_score_dialog::~t_high_score_dialog()
{
}
